package com.example.nonacademic_education.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.example.nonacademic_education.constant.Constant;
import com.example.nonacademic_education.dao.*;
import com.example.nonacademic_education.data.request.FileApplyVo;
import com.example.nonacademic_education.data.request.FileInfoR;
import com.example.nonacademic_education.data.request.UploadFileInfo;
import com.example.nonacademic_education.data.response.UploadFileInfoDto;
import com.example.nonacademic_education.entity.FileApply;
import com.example.nonacademic_education.entity.FileInfo;
import com.example.nonacademic_education.service.FileService;
import com.example.nonacademic_education.util.FileUtils;
import com.example.nonacademic_education.util.MyZipUtil;
import com.example.nonacademic_education.util.R;
import com.example.nonacademic_education.util.ZipUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author xinmiao
 * @description
 * @date 2023/4/18 11:18
 */
@Service
@Slf4j
public class FileServiceImpl implements FileService {
    @Resource
    private FileDao fileDao;
    @Resource
    private FileApplyDao fileApplyDao;
    @Resource
    private DepartmentDao departmentDao;
    @Resource
    private MyZipUtil myZipUtil;
    @Resource
    private ProjectDao projectDao;
    @Resource
    private AdminDao adminDao;
    @Resource
    private UserDao userDao;
    @Resource
    private FileUtils fileUtils;
    @Override
    public R upload(UploadFileInfo fileInfo, MultipartFile[] files) {
        //Long isExist=fileApplyDao.findNecessaryByFileInfo(fileInfo.getYear(),fileInfo.getProjectId(),Constant.NO_PASS);
        Long isExist=fileApplyDao.findNecessaryByFileInfo(fileInfo.getProjectId());
        List<String> filenames=new ArrayList<>();
        if (isExist!=null&&fileInfo.getIsNecessary()==1){
            return R.error("已有必要资料的上传记录");
        }
        if (isExist==null&&fileInfo.getIsNecessary()==0){
            return R.error("请先上传必要资料");
        }
        String pre=fileInfo.getYear()+Constant.SPACE+fileInfo.getProjectName()+ Constant.SPACE;
        Long uuid=System.currentTimeMillis();
        fileApplyDao.addOne(fileInfo.getYear(),fileInfo.getProjectId(),fileInfo.getIsNecessary(), Constant.NO_PASS,fileInfo.getNote(),uuid,0L);
        Long applyId=fileApplyDao.findIdByFileInfo(fileInfo.getYear(),fileInfo.getProjectId(),fileInfo.getIsNecessary(), Constant.NO_PASS,uuid,0L);
        File dir = new File(Constant.proBiologyImagePath);
        if (!dir.exists()) {
            dir.mkdir();
        }
        for (MultipartFile file : files) {
            String filename = file.getOriginalFilename();
            pre+=filename;
            File newFile = new File(Constant.proBiologyImagePath + pre);
            try {
                file.transferTo(newFile);
            } catch (IOException e) {
                e.printStackTrace();
                //持久化到数据库
                filenames.add(filename);
            }
        }
        Map<String,Object> data=new HashMap<>();
        data.put("failed",filenames);
        fileDao.addBatch(pre,fileInfo.getFiles(),Constant.SERVE_URL+Constant.GET_FILE_URL+pre,applyId,fileInfo.getDepartmentId(),fileInfo.getProjectId(),fileInfo.getIsNecessary(),fileInfo.getYear(),0L);
        return R.ok(data,"success");
    }

    @Override
    public R upload(MultipartFile file,Integer year,String projectName) {
        //改变了命名规则：
        long timestamp = System.currentTimeMillis();
        String pre=year+Constant.FILE_SLASH+projectName+Constant.FILE_SLASH;
        File dir=new File(Constant.proBiologyImagePath+pre);
        if (!dir.exists()){
            dir.mkdirs();
        }
        String filename = (timestamp%100000L)+file.getOriginalFilename();
        pre+=filename;
        File newFile = new File(Constant.proBiologyImagePath + pre);
        try {
            file.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
            return R.error("文件'"+filename+"'上传失败");
        }
        Map<String,Object> data=new HashMap<>();
        data.put("url",Constant.SERVE_URL+Constant.GET_FILE_URL+pre);
        return R.ok(data,"上传成功");
    }

    @Override
    public R multiConditionQuery(FileInfoR fileInfoR, Integer page, Integer size) {
        if (page < 1) {
            return R.error("page couldn't less than 1");
        } else {
            if (fileInfoR.getDepartmentId() == null) {
                fileInfoR.setDepartmentId(adminDao.getDepartmentIdByUsername(StpUtil.getLoginIdAsString()));
            }
            page = (page - 1) * size;
            Map<String,Object> data=new HashMap<>();
            data.put("list",fileDao.multiConditionQuery(fileInfoR,page,size));
            data.put("total",fileDao.countMultiConditionQuery(fileInfoR));
            return R.ok(data,"success");
        }
    }

    @Override
    public void download(List<Long> ids, HttpServletResponse response,Long userId) throws IOException {
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        List<String> paths=fileDao.getPathsByIds(ids,Constant.PATH_POSITION);
        List<File> files=new ArrayList<>();
        for (String s : paths) {
            files.add(new File(Constant.proBiologyImagePath+Constant.FILE_PATH+s));
        }
        //log.info("files.size():"+files.size());
        if (paths.size()<2){
            //普通下载
            fileUtils.downloadNormalFile(Constant.proBiologyImagePath+Constant.FILE_PATH+paths.get(0),response);
            return;
        }
        // 先在D盘创建一个压缩包
        String downloaderName=userDao.getNameById(userId);
        File zipFile=new File(Constant.proBiologyImagePath+Constant.FILE_PATH+downloaderName+userId+".zip");
        if(!zipFile.exists()) {
            try {
                zipFile.createNewFile();
                // 将package.zip的File对象传到toZip对象中
                ZipUtils.toZip(files, zipFile);
//                for (File value : files) {
//                    value.delete();
//                }
            } catch (IOException e) {
                e.printStackTrace();
                //失败数组存储在日志中
            }
        }
        myZipUtil.getZip(userId,response,downloaderName);
    }

    @Override
    public R getApplyList(FileApplyVo fileApply, Long departmentId, Integer page, Integer size) {
        if (page < 1) {
            return R.error("page couldn't less than 1");
        } else {
            departmentId=fileApply.getDepartmentId();
            page = (page - 1) * size;
            Map<String,Object> data=new HashMap<>();
            if (departmentId == null) {
                departmentId=adminDao.getDepartmentIdByUsername(StpUtil.getLoginIdAsString());
            }
            List<Long> applyIds=fileApplyDao.getIdsByMulti(fileApply,departmentId,page,size);
//            if(fileApply.getIsPass()==2){
//                fileApply.setIsPass(1);
//                applyIds=fileApplyDao.getIdsByMulti(fileApply,departmentId,page,size);
//            }else if (fileApply.getIsPass()==1){
//                applyIds=fileApplyDao.getIdsByMulti1(fileApply,departmentId,page,size);
//            }else {
//                applyIds=fileApplyDao.getIdsByMulti2(fileApply,departmentId,page,size);
//            }
            if (applyIds.isEmpty()) {
                data.put("list",new ArrayList<>());
                data.put("total",0);
                return R.ok(data,"success");
            }
            List<UploadFileInfoDto> list = fileApplyDao.getApplyList(applyIds);
            Integer total=fileApplyDao.countApplyList(fileApply, departmentId);
            if (departmentId!=null){
                if (departmentId==0L){
                    for (UploadFileInfoDto uploadFileInfoDto : list) {
                        uploadFileInfoDto.setDepartmentId(projectDao.getDepartmentIdById(uploadFileInfoDto.getProjectId()));
                        uploadFileInfoDto.setDepartmentName(departmentDao.getNameById(uploadFileInfoDto.getDepartmentId()));
                    }
                }else {
                    String departmentName=departmentDao.getNameById(departmentId);
                    for (UploadFileInfoDto uploadFileInfoDto : list) {
                        uploadFileInfoDto.setDepartmentId(departmentId);
                        uploadFileInfoDto.setDepartmentName(departmentName);
                    }
                }
            }
            data.put("list",list);
            data.put("total",total);
            return R.ok(data,"success");
        }
    }

    @Override
    public R audit(Long fileId, Integer isPass,Long applyId,String cause) {
        if (isPass==0){
            fileDao.noPass(fileId,cause);
        }else {
            fileDao.pass(fileId);
        }
        if (isPass==1){
            Integer noPass=fileDao.getNoPassByApplyId(applyId);
            if (noPass==0){
                fileApplyDao.updateIsPassById(applyId);
            }
        }
        return R.ok("success");
    }

    @Override
    public R reload(Long id, MultipartFile file) {
        FileInfo fileInfo=fileDao.getOneById(id);
        if (fileInfo.getAuditStatus()==2){
            return R.error("该文件不能更新了");
        }
        String oldPath=fileInfo.getUrl().substring(Constant.PATH_POSITION-1);
        //不删除旧文件，做保留操作
        //File oldFile=new File(Constant.proBiologyImagePath+Constant.FILE_PATH+oldPath);
        //oldFile.delete();
        String pre=oldPath.substring(0,oldPath.lastIndexOf('/')+1)+System.currentTimeMillis()/100000L+file.getOriginalFilename();
        String filename=Constant.proBiologyImagePath+Constant.FILE_PATH+pre;
        String url=Constant.SERVE_URL+Constant.GET_FILE_URL+pre;
        File newFile=new File(filename);
        try {
            file.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
            return R.error("文件更新失败");
        }
        //做保留操作
//        if (fileDao.updateAuditStatusTo0(id,file.getOriginalFilename(),url)==1){
//            return R.ok("success");
//        }else {
//            return R.error("更新数据库失败");
//        }
        Integer version=fileDao.getMaxVersionBySourceId(fileInfo.getSourceId())+1;
        fileInfo.setVersion(version);
        if (fileInfo.getNote()==null||fileInfo.getNote().equals("")) {
            fileInfo.setNote("这是"+fileInfo.getName()+"重新上传的第 "+version+" 版");
        }
        if (fileDao.addReUploadFile(id,file.getOriginalFilename(),url,fileInfo)==1){
            return R.ok("success");
        }else {
            return R.error("更新数据库失败");
        }
    }

    @Override
    public R apply(UploadFileInfo fileInfo) {
        if (fileInfo.getFiles().isEmpty()) {
            return R.error("文件列表为空，取消提交");
        }
        String username;
        try {
            username=StpUtil.getLoginIdAsString();
        }catch (Exception e){
            return R.error("获取上传者信息失败");
        }
        if (fileInfo.getDepartmentId()==null||fileInfo.getDepartmentId()==0L){
            fileInfo.setDepartmentId(adminDao.getDepartmentIdByUsername(username));
            if (fileInfo.getDepartmentId()==null||fileInfo.getDepartmentId()==0L){
                return R.error("获取办学单位信息失败");
            }
        }
        fileInfo.setUploaderId(adminDao.getIdByUsername(username));
        //Long isExist=fileApplyDao.findNecessaryByFileInfo(fileInfo.getYear(),fileInfo.getProjectId(),Constant.NO_PASS);
        Long isExist=fileApplyDao.findNecessaryByFileInfo(fileInfo.getProjectId());

        if (isExist!=null&&fileInfo.getIsNecessary()==1){
            return R.error("已有必要资料的上传记录，不允许重复提交表单；如需修改/重传某个文件，请在下方列表重传新的文件");
        }
        if (isExist==null&&fileInfo.getIsNecessary()==0){
            return R.error("请先上传必要资料");
        }
        String pre=fileInfo.getYear()+Constant.SPACE+fileInfo.getProjectName()+ Constant.SPACE;
        Long uuid=System.currentTimeMillis();
        fileApplyDao.addOne(fileInfo.getYear(),fileInfo.getProjectId(),fileInfo.getIsNecessary(), Constant.NO_PASS,fileInfo.getNote(),uuid,fileInfo.getUploaderId());
        Long applyId=fileApplyDao.findIdByFileInfo(fileInfo.getYear(),fileInfo.getProjectId(),fileInfo.getIsNecessary(), Constant.NO_PASS,uuid,fileInfo.getUploaderId());

        fileDao.addBatch(pre,fileInfo.getFiles(),Constant.SERVE_URL+Constant.GET_FILE_URL+pre,applyId,fileInfo.getDepartmentId(),fileInfo.getProjectId(),fileInfo.getIsNecessary(),fileInfo.getYear(),fileInfo.getUploaderId());
        fileDao.setSourceId(applyId);
        return R.ok("success");
    }

    @Override
    public R deleteFiles(List<Long> ids,Long applyId) {
        fileDao.deleteByIds(ids);
        Integer n=fileDao.countByApplyId(applyId);
        if (n==0){
            fileApplyDao.deleteById(applyId);
        }
        return R.ok("删除成功");
    }

    private byte[] getStream(String filePath) {
        byte[] buffer = null;
        File file = new File(filePath);
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            bos = new ByteArrayOutputStream();
            fis = new FileInputStream(file);
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(fis!=null) {
                    fis.close();
                }
                if(bos!=null) {
                    bos.close();
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
        return buffer;
    }
}
